package primetest.impl.controler;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.security.RolesAllowed;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import primetest.dto.DepartmentDto;
import primetest.dto.DoctorDto;
import primetest.dto.MedicineDto;
import primetest.dto.RoleDto;
import primetest.faces.DoctorListModel;
import primetest.faces.RoleListModel;
import primetest.impl.dictionary.Dictionary;
import primetest.impl.manager.SessionManager;
import primetest.impl.service.DepartmentService;
import primetest.impl.service.DoctorService;
import primetest.impl.service.RoleService;

@Named("doctorMeintenanceControler")
@SessionScoped
@RolesAllowed("admin")
public class DoctorMeintenanceControler implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = 2135960267327011165L;

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Inject
	private Conversation conversation;
	@Inject
	private Dictionary dictionary;

	private List<DepartmentDto> departmentList = null;
	private List<RoleDto> roleList = null;
	private List<DoctorDto> baseDoctorList = null;
	private DoctorListModel doctorList = null;

	private DepartmentDto selectedDepartmentDto = null;
	private int first;

	private boolean editMode = false;
	private boolean addMode = false;
	private boolean passwordEdit = false;

	private String password;
	private String passwordConfirm;

	private DoctorDto selectedDoctor;
	private DoctorDto editDoctor = new DoctorDto();

	@Inject
	private DepartmentService departmentService;
	@Inject
	private RoleService roleService;
	@Inject
	private DoctorService doctorService;
	@Inject
	private SessionManager sessionManager;

	private RoleListModel roleListModel;
	private RoleDto[] roleSelection;

	private List<DoctorDto> filteredTerms;

	@RolesAllowed("admin")
	public DoctorListModel getDoctorList() throws IOException {
		if (baseDoctorList == null) {
			try {
				if (selectedDepartmentDto != null) {
					baseDoctorList = doctorService
							.getDoctorListByDepartment(selectedDepartmentDto
									.getSeq());

				} else {
					baseDoctorList = doctorService.getDoctorList();
				}
				doctorList = new DoctorListModel(baseDoctorList);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		if (roleList == null) {
			roleList = roleService.getAllList();
		}
		return baseDoctorList == null ? new DoctorListModel(
				new ArrayList<DoctorDto>()) : doctorList;
	}

	private void innerDataClear() {
		selectedDepartmentDto = null;
		baseDoctorList = null;
		selectedDoctor = null;
		first = 0;
	}

	public void reload() {
		baseDoctorList = null;
		// conversationBegin();
	}

	public DoctorDto getSelectedDoctor() {
		return selectedDoctor;
	}

	public void setSelectedDoctor(DoctorDto selectedDoctor) {
		this.selectedDoctor = selectedDoctor;
	}

	public List<DepartmentDto> getDepartmentList() throws IOException {
		departmentList = departmentService.getDepartmentList();
		return departmentList;
	}

	public int getSelectedDepartment() {
		if (selectedDepartmentDto == null) {
			return -1;
		} else {
			return selectedDepartmentDto.getSeq();
		}
	}

	public void setSelectedDepartment(int selectedDepartment)
			throws IOException {
		if (selectedDepartment == -1) {
			this.selectedDepartmentDto = null;
			return;
		}
		if (selectedDepartmentDto == null
				|| this.selectedDepartmentDto.getSeq() != selectedDepartment) {
			innerDataClear();
			this.selectedDepartmentDto = departmentService
					.getDepartment(selectedDepartment);
		}
	}

	public List<RoleDto> getRoleList() throws IOException {
		if (roleList == null) {
			roleList = roleService.getAllList();
		}
		return roleList;
	}

	public int getFirst() {
		return first;
	}

	public void setFirst(int first) {
		this.first = first;
	}

	public boolean isEditMode() {
		return editMode;
	}

	public void setEditMode(boolean editMode) {
		this.editMode = editMode;
	}

	public boolean isAddMode() {
		return addMode;
	}

	public void setAddMode(boolean addMode) {
		this.addMode = addMode;
	}

	public boolean isBrowseMode() {
		return !addMode && !editMode;
	}

	public void startEdit() throws IOException {
		editDoctor = new DoctorDto();
		editDoctor.setAll(selectedDoctor);
		makeRoleListModel(editDoctor);
		editMode = true;
	}

	public void startAdd() throws IOException {
		editDoctor = new DoctorDto();
		editDoctor.setDepartmentDto(selectedDepartmentDto);
		makeRoleListModel(editDoctor);
		addMode = true;
	}

	private void makeRoleListModel(DoctorDto doctorDto) throws IOException {
		List<RoleDto> roleList = roleService.getAllList();
		roleListModel = new RoleListModel(roleList);
		roleSelection = new RoleDto[doctorDto.getRoleList().size()];
		int i = 0;
		for (RoleDto roleDto : doctorDto.getRoleList()) {
			roleSelection[i++] = roleListModel.getRowData(roleDto.getRole());
		}
	}

	public RoleListModel getRoleListModel() {
		return roleListModel;
	}

	public void setRoleListModel(RoleListModel roleListModel) {
		this.roleListModel = roleListModel;
	}

	public RoleDto[] getRoleSelection() {
		return roleSelection;
	}

	public void setRoleSelection(RoleDto[] roleSelection) {
		this.roleSelection = roleSelection;
	}

	public void startPasswordEdit() {
		passwordEdit = true;
	}

	public void deleteDoctor() throws IOException {
		try {
			if (selectedDoctor.getId() == sessionManager.getLoginUser().getId()) {
				sessionManager.addGlobalMessageFatal("Cannot delete yourself",
						null);
				return;
			}
			doctorService.deleteDoctor(selectedDoctor.getId());
		} catch (IOException e) {
			logger.error("Doctor Date delete error.", e);
			sessionManager.addGlobalMessageFatal("Doctor Data delete error.",
					null);
			throw e;
		}
	}

	public void apply() throws IOException {
		try {
			editDoctor.setDepartmentDto(departmentService
					.getDepartment(editDoctor.getDepartmentDtoSeq()));
			editDoctor.saveDate();
			if (roleSelection.length < 1) {
				sessionManager.addGlobalMessageFatal(
						dictionary.get("Role is required."), null);
				return;
			}
			editDoctor.getRoleList().clear();
			for (RoleDto roleDto : roleSelection) {
				editDoctor.getRoleList().add(roleDto);
			}
			if (editDoctor.isChangePassword()
					&& (editDoctor.getPlanePassword() == null || editDoctor
							.getPlanePassword().equals(""))) {
				sessionManager.addGlobalMessageFatal(
						dictionary.get("Password is required."), null);
				return;
			}
			if (addMode
					&& doctorService.findDoctorById(editDoctor.getId()) != null) {
				sessionManager.addGlobalMessageFatal(dictionary
						.get("ID already exists, please change another id"),
						null);
				return;
			}
			if (editMode) {
				doctorService.updateDoctor(editDoctor);
				replaceDoctorData(editDoctor);
			} else {
				if (!editDoctor.isChangePassword()) {
					sessionManager.addGlobalMessageFatal(
							dictionary.get("Password is required."), null);
					return;
				}
				doctorService.addDoctor(editDoctor);
			}
			if (addMode) {
				baseDoctorList = null;
			}
			editDoctor = null;
			editMode = false;
			addMode = false;
		} catch (IOException e) {
			logger.error("Doctor Date update error.", e);
			sessionManager.addGlobalMessageFatal("Doctor Data update error.",
					null);
			throw e;
		}
	}

	private void replaceDoctorData(DoctorDto updatedDoctorDto)
			throws IOException {
		int index = findDoctorData(updatedDoctorDto.getId());
		if (index >= 0) {
			baseDoctorList.get(index).setAll(updatedDoctorDto);
		}
	}

	private int findDoctorData(String id) {
		for (int i = 0; i < baseDoctorList.size(); i++) {
			DoctorDto doctorDto = baseDoctorList.get(i);
			if (doctorDto.getId().equals(id)) {
				return i;
			}
		}
		return -1;
	}

	public void discard() {
		editDoctor = new DoctorDto();
		editMode = false;
		addMode = false;
		passwordEdit = false;
	}

	public boolean isPasswordEdit() {
		return passwordEdit;
	}

	public void setPasswordEdit(boolean passwordEdit) {
		this.passwordEdit = passwordEdit;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPasswordConfirm() {
		return passwordConfirm;
	}

	public void setPasswordConfirm(String passwordConfirm) {
		this.passwordConfirm = passwordConfirm;
	}

	public void applyPassword() {
		if (password.isEmpty()) {
			sessionManager.addGlobalMessageFatal(
					dictionary.get("Password cannot be empty"), null);
			return;
		}
		if (password.equals(passwordConfirm)) {
			editDoctor.setPlanePassword(password);
			passwordEdit = false;
		} else {
			sessionManager.addGlobalMessageFatal(
					dictionary.get("PasswordConfirmNotEqual"), null);
		}
	}

	public void discardPassword() {
		passwordEdit = false;
	}

	public DoctorDto getEditDoctor() {
		return editDoctor;
	}

	public void setEditDoctor(DoctorDto editDoctor) {
		this.editDoctor = editDoctor;
	}

	// public void conversationBegin(){
	// if(conversation.isTransient()){
	// conversation.begin();
	// }
	// }
	// public void conversationEnd(){
	// if(!conversation.isTransient()){
	// conversation.end();
	// }
	// }

	public String returnToMenu() {
		// conversationEnd();
		return "/faces/MainMenu?faces-redirect=true";
	}

	public String getConversationState() {
		return conversation.isTransient() ? "not conv" : "conv";
	}

	public static final String MATCH_MAIL = "([a-zA-Z0-9][a-zA-Z0-9_.+\\-]*)@(([a-zA-Z0-9][a-zA-Z0-9_\\-]+\\.)+[a-zA-Z]{2,6})";

	public void emailValidate(FacesContext context, UIComponent component,
			Object value) {
		String text = value.toString();
		if (!text.matches(MATCH_MAIL)) {
			sessionManager.addGlobalMessageFatal(
					dictionary.get("invalidEmail"), null);
			// throw new ValidatorException(new
			// FacesMessage(FacesMessage.SEVERITY_FATAL,
			// dictionaryControler.getDictionary("invalidEmail"), null));
		}
	}

	public String logoff() {
		// conversationEnd();
		sessionManager.logoff();
		return "/faces/MainMenu.jsf?faces-redirect=true";
	}

	public List<DoctorDto> getFilteredTerms() {
		return filteredTerms;
	}

	public void setFilteredTerms(List<DoctorDto> filteredTerms) {
		this.filteredTerms = filteredTerms;
	}

}
